/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include <mutex>
#include <set>
//#include <stack>

#include <基本类型.h>
#include <S_键值序列容器.h>
#include <core/文件块.h>

#include "节点.h"
#include "编译声明代码.h"


typedef bool(*f_JIT_接口函数指针_class)(void* self, E_JIT_FunParam* 参数, uint8 参数数量);
typedef void(*f_JIT_接口函数指针初始化)(E_JIT_FunParam* 参数);
typedef C_节点基类*(*fp_创建节点函数)(S_设备环境& ctx, class C_节点树* 子节点树);

struct S_Scene;
struct S_物理解算器;


enum E_节点树更新方式 {
	e_手动更新,
	e_帧更新,
	e_实时更新,
	e_离线更新,
};


typedef enum : uint64 {
	//e_节点编译_外部调用 = DEF_字符串拼接ID('e', 'x', 'p', 'o', 'r', 't', '\0', '\0', '\0'),
	//e_节点编译_内联调用 = DEF_字符串拼接ID('i', 'n', 'l', 'i', 'n', 'e', '\0', '\0', '\0'),
	e_节点编译_重新编译 = 0,
	e_节点编译_外部调用 = 1 << 0,
	e_节点编译_内联调用 = 1 << 1,
	e_节点编译_完成 = e_节点编译_外部调用 | e_节点编译_内联调用,
}E_节点树编译位标志;

typedef enum : uint64 {
	e_编译目标代码_CPU = DEF_字符串拼接ID('C', 'p', 'u', '\0', '\0', '\0', '\0', '\0'),
	e_编译目标代码_rCall = DEF_字符串拼接ID('r', 'C', 'a', 'l', 'l', '\0', '\0', '\0'),
	e_编译目标代码_Frag = DEF_字符串拼接ID('F', 'r', 'a', 'g', '\0', '\0', '\0', '\0'),
	e_编译目标代码_Geom = DEF_字符串拼接ID('G', 'e', 'o', 'm', '\0', '\0', '\0', '\0'),
}E_编译目标代码;


struct S_节点链接线记录 {
	struct S_节点链接线链接到输出插座记录 {
		std::u16string	m_链接到的输出插座所在节点;
		int16			m_链接到的输出插座ID;
	};

	std::u16string	m_当前节点名称;
	uint32			m_当前节点输入插座ID;

	std::vector<S_节点链接线链接到输出插座记录> m_链接到输出插座;
};


struct S_节点组 {
	std::vector<C_节点基类*> m_组;
	std::u16string           m_Name;
	uint32                   m_Type;
};


class C_节点树 {
	//S_Scene*			m_当前场景;
	E_节点树更新方式	m_更新方式;
	C_节点基类*			m_父节点;
	

protected:
	bool				m_开启标记循环内部节点;
	uint32				m_JIT参数ID;


public:
	C_节点树(const std::u16string&  idName);
	~C_节点树();

	std::set<C_节点基类*>		m_Nodes;
	std::u16string				m_IDName;
	uint32						m_ID;
	E_节点树类型				m_树类型;
	
	std::mutex								m_节点更新锁;
	std::vector<std::vector<C_节点基类*>>	m_层更新节点;
	std::vector<C_节点基类*>				m_开始节点;
	uint32									m_中断层;

	//std::vector<S_节点组*>					m_节点组;

	C_节点基类* m_全局变量;
	bool		m_全局变量引用;

	C_节点基类* m_成员变量;
	bool		m_成员变量引用;

	C_节点基类* m_网格属性变量;
	bool		m_网格属性引用;


	//vec2		m_中心;
	//vec2		m_边界;
	static C_StrKey分配器    g_函数名称分配;
	API_EXPORT static C_StrKey分配器    g_树名称分配;
	
	static uint8             G_编译优化;
	static std::mutex	     g_分配内存锁;
	//static std::vector<E_JIT_FunParam>		G节点JIT参数;
	static std::vector<void**> g_节点JIT参数;
	static std::vector<uint32> g_JIT一级参数删除记录;


	//std::vector<void*> m_节点JIT参数;
	std::vector<void*> m_JIT二级参数;
	uint32             m_参数全局偏移;


	std::mutex      m_编译状态锁;
	uint64          m_以编译;


	static bool	g_节点是否可编辑;
	bool		m_节点结构改变;
	bool		m_开启帧更新;
	
	bool		m_未保存或加载;
	bool		m_以删除;
	uint64		m_程序集;
	uint64		m_函数指针;
	bool		m_开始编译;
	bool		m_编译以准备好;
	//E_JIT方式	m_编译方式;
	//std::string m_Code;
	std::set<C_节点基类*> m_节点树绑定的父节点;

	static C_节点树* f_get节点树(const std::u16string& key);

	void		     f_set父节点(C_节点基类* node) { 
		m_父节点 = node; 
	}
	C_节点基类*	f_get父节点() { 
		if(m_节点树绑定的父节点.size()) return *m_节点树绑定的父节点.begin();
		return m_父节点; 
	}
	
	std::string f_getName();



	S_Props		m_函数名称;
	S_Props		m_外部加载;
	S_Props		m_代码文件路径;
	S_Props		m_编译方式;
	
	std::string		m_Code;
	std::string		m_ReleaseCode;
	E_编译目标代码	m_目标代码;
	E_方向			m_布局方向;
	


	void		f_准备Update();
	void		f_标记区域节点(C_节点基类* node);
	bool		f_Update(uint32 层ID);
	std::string	f_编译一层节点(uint32 层ID, std::string& 声明, std::vector<std::string>& 定义, std::string& 释放);
	//static uint16		f_genJIT参数ID();
	uint32		f_gen参数ID();
	void		f_准备编译节点树();
	bool		f_加载程序集(const std::string& 文件路径, E_JIT方式 方式);

	
	void		f_添加节点(C_节点基类* node);
	void		f_删除节点(C_节点基类* node);

	uint32		f_getNodeNum();

	C_节点基类*		f_getNode(const std::string& key);
	//S_物理解算器*	f_get物理引擎();

	void		f_重置节点更新时间();
	void		f_重置节点名称();
	void		f_reset();
	
	C_节点树*	f_拷贝();
	C_节点树*	f_getThisTree();

protected:
	void		f_查找开始节点();
	void		f_准备帧Update();
	//void	f_取首节点是否要更新(vector<bool>& start);
	//void	f_帧更新节点标记为已更新();
	
	void	f_计算节点层级();
	void	f_推进节点层级计算(std::vector<C_节点基类*>& nodes, uint32 depth);
	//void	f_节点更新_释放上一层数据();

private:



};





inline C_节点树* f_getTree(const std::u16string& treeName) {
	C_节点树* tree = C_节点树::f_get节点树(treeName);

	if (!tree) {
		tree = new C_节点树(treeName);
	}

	return tree;
}



API_EXPORT C_节点树* f_node_Create节点树(bool isRootNode, std::u16string name = u"物体");
API_EXPORT C_节点树* f_node_Create包节点树(bool isRootNode, std::u16string name = u"包");
API_EXPORT C_节点树* f_node_Create渲染节点树(bool isRootNode, std::u16string name = u"渲染");
API_EXPORT C_节点树* f_node_Create几何节点树(bool isRootNode, std::u16string name = u"geom_");
API_EXPORT C_节点树* f_node_Create函数节点树(bool isRootNode, std::u16string name = u"函数");
API_EXPORT C_节点树* f_node_Create循环节点树(bool isRootNode, std::u16string name = u"循环");
API_EXPORT C_节点树* f_node_Create材质节点树(bool isRootNode, std::u16string name = u"材质");
API_EXPORT C_节点树* f_node_Create着色节点树(bool isRootNode, std::u16string name = u"着色");
API_EXPORT C_节点树* f_node_Create纹理节点树(bool isRootNode, std::u16string name = u"纹理");
API_EXPORT C_节点树* f_node_Create物理节点树(bool isRootNode, std::u16string name = u"物理");
API_EXPORT C_节点树* f_node_Create并行节点树(bool isRootNode, std::u16string name = u"并行");
API_EXPORT C_节点树* f_node_Create几何着色节点树(bool isRootNode, std::u16string name = u"几何着色");

API_EXPORT void f_NT_销毁节点(C_节点树* t);
API_EXPORT void f_NT_Release(C_节点树* t);
API_EXPORT void f_node_帧更新(bool t);
API_EXPORT bool f_node_帧是否更新();



//void f_NT_准备帧更新节点(C_节点树* tree);
API_EXPORT void f_NT_刷新全局参数(C_节点树* tree);
API_EXPORT void f_NT_冻结节点(C_节点基类* rn, bool 冻结);
API_EXPORT void f_NT_预处理冻结节点(C_节点树* tree);
API_EXPORT bool f_NT_StepUpdate节点(C_节点树* tree, bool 帧更新);
API_EXPORT bool f_NT_编译节点(C_节点基类* rn, std::string path, bool 编译成动态链接库 = false);

API_EXPORT std::string f_NT_编译节点树(C_节点树* tree, std::vector<std::string>& 定义, std::string& 声明);
API_EXPORT uint64      f_NT_初始化函数接口(uint64 程序集, std::string 函数名称, E_JIT方式 方式 = E_JIT方式::e_jit_llvm);
API_EXPORT bool        f_NT_是否内联调用(C_节点基类* node);
API_EXPORT uint8* f_NT_序列化节点组数据(C_节点树* tree, S_文件块& 文件块);
API_EXPORT void f_NT_读取节点组数据(C_节点树* tree);
API_EXPORT void f_NT_保存节点组数据(C_节点树* tree);
API_EXPORT void f_NT_构建框节点依赖结构(C_节点基类* 当前框节点, std::vector<C_节点基类*>& 框包含节点, std::map<std::u16string, C_节点基类*>& 新节点集);


API_EXPORT std::string f_代码构建_属性变量(S_Props& prop, C_节点树* rt);
API_EXPORT void		f_代码构建_属性变量传至GPU(S_Props& prop);
API_EXPORT std::string f_代码构建_变量(C_节点树* rt, void* data, E_值类型 type);
API_EXPORT std::string f_代码构建_插座变量数组数量(C_插座基类& socket, std::string& name, int32 loc = 0);


Inline std::string f_代码构建_节点树输出变量名称(C_节点树* rt, uint32 id) {
	return rt->f_getName() + "OutParam" + f_整数值转字符串(id);
}
Inline std::string f_代码构建_节点树输出变量名称(C_节点基类* rn, uint32 id) {
	return rn->f_getName() + "OutParam" + f_整数值转字符串(id);
}

Inline bool f_代码构建_数组指针(C_插座基类* socket) {
	return f_代码构建_是否为数组(socket->m_Type);
}

Inline bool f_代码构建_是否为指针(E_值类型 type) {
	switch (type) {
		case E_值类型::e_Type_Mesh:
		case E_值类型::e_Type_Mesh_1D:
		case E_值类型::e_Type_多边形:
		case E_值类型::e_Type_多边形_1D:
		
		case E_值类型::e_Type_多边形边:
		case E_值类型::e_Type_多边形边1D:
		
		case E_值类型::e_Type_多边形元素:
		case E_值类型::e_Type_多边形元素1D:
		case E_值类型::e_Type_多边形面:
		case E_值类型::e_Type_网格自定义属性:

		case E_值类型::e_Type_Bool_1D:
		case E_值类型::e_Type_Vec2_1D:
		case E_值类型::e_Type_Vec3_1D:
		case E_值类型::e_Type_Vec4_1D:
		case E_值类型::e_Type_Mat4X4_1D:
		
		case E_值类型::e_Type_I8_1D:
		case E_值类型::e_Type_I32_1D:
		case E_值类型::e_Type_UI32_1D:
		case E_值类型::e_Type_UI32_2D:
		case E_值类型::e_Type_F32_1D:
		case E_值类型::e_Type_iVec2_1D:
		case E_值类型::e_Type_iVec3_1D:
		case E_值类型::e_Type_iVec4_1D:

		case E_值类型::e_Type_uVec2_1D:
		case E_值类型::e_Type_uVec3_1D:

		case E_值类型::e_Type_iVec3_2D:
		//case E_值类型::e_Type_uVec4_1D:
		case E_值类型::e_Type_Vec3_2D:

		case E_值类型::e_Type_Bounding_1D:

		case E_值类型::e_Type_材质1D:
		case E_值类型::e_Type_纹理_1D:

		case E_值类型::e_Type_Object:
		case E_值类型::e_Type_Object_1D:
		case E_值类型::e_Type_LineStr1D:
		//case E_值类型::e_Type_Str:
		case E_值类型::e_Type_纹理:
		case E_值类型::e_Type_Array:
			return true;
	}
	return false;
}


Inline std::string f_代码构建_节点树输入输出变量引用(E_值类型 type, uint32 id) {
	std::string 参数名称;

	if (f_代码构建_是否为指针(type)) {
		参数名称 = "((" + f_node_getTypeName(type) + "*)(inData[" + f_整数值转字符串(id) + "]))";
	}
	else {
		参数名称 = "*((" + f_node_getTypeName(type) + "*)(inData[" + f_整数值转字符串(id) + "]))";
	}
	return 参数名称;
}

API_EXPORT void f_代码构建_输入输出节点参数(C_节点基类* rn, std::vector<C_节点基类*>& m_InNodes, const std::vector<C_节点基类*>& m_OutNudes);

API_EXPORT void f_构建代码_分配渲染器GPU属性变量(S_Props& prop);
API_EXPORT void f_构建代码_释放渲染器GPU属性变量(S_Props& prop);
API_EXPORT void f_构建代码_构建GPU插座变量(C_插座基类& socket);
API_EXPORT void f_构建代码_释放GPU插座变量(C_插座基类& socket);


API_EXPORT int32 f_代码构建_编译着色器(std::string glsl文件路径, std::string SPV文件路径);








